/// \brief Class which handles time. Can use astronomic and "human readable" time.
/// \file clock.h
/// \version 0.1
/// \author Yann de Thé
/// \date September 20th 2011

// Copyright (C) 2009  Yann de The
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


#include "SEClock.h"


SEClock::SEClock() {
    this->setToPresentTime();
    _tic_time_1 = _time;
    _init_time = _time;
}

SEClock::~SEClock() {
    
}

double SEClock::tic() {
    double dt = this->getPresentTime() - _tic_time_1;
    
    _tic_time_1 += dt;
    
    return dt;
}

void SEClock::setToPresentTime() {
    boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
    boost::posix_time::time_duration td = now - boost::posix_time::ptime(boost::gregorian::date(1970, boost::gregorian::Jan, 1));
    
    _time = double(td.total_microseconds())/1e6;
}

double SEClock::getPresentTime() const {
    boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
    boost::posix_time::time_duration td = now - boost::posix_time::ptime(boost::gregorian::date(1970, boost::gregorian::Jan, 1));
    
    return double(td.total_microseconds())/1e6;
}


void SEClock::update(double dt) {
    _time += dt;
}

double SEClock::getSimMJD() const {
    return 2440587.5 + _time/86400.0;
}

Date SEClock::getSimDate() const {
    Date date;
    double JD = this->getSimMJD();
    
    int A,a,B,C,D,E;
    double F,Z;
    
    JD += 0.5;
    Z = (int) JD;
    F = JD - Z;
    
    if (Z < 2299161)
        A = (int) Z;
    else {
        a = (int) ((Z - 1867216.25) / 36524.25);
        A = (int) (Z + 1 + a - (int)(a / 4));
    }
    
    B = A + 1524;
    C = (int) ((B - 122.1) / 365.25);
    D = (int) (365.25 * C);
    E = (int) ((B - D) / 30.6001);
    
    /* get the hms */
    date.hours = (int) (F * 24);
    F -= (double)date.hours / 24;
    date.minutes = (int) (F * 1440);
    F -= (double)date.minutes / 1440;
    date.seconds = F * 86400;
    
    /* get the day */
    date.days = B - D - (int)(30.6001 * E);
    
    /* get the month */
    if (E < 14)
        date.months = E - 1;
    else
        date.months = E - 13;
    
    /* get the year */
    if (date.months > 2)
        date.years = C - 4716;
    else
        date.years = C - 4715;
    
    return date;
    
}

double SEClock::getSimDuration() const {
    return _time - _init_time;
}

double SEClock::getSimTime() const {
    return _time;
}


void SEClock::setSimDate(Date& date) {
    double JD;
    double days;
    int a,b;
    Date local_date;
    
	/* create local copy */
    memcpy (&local_date, &date, sizeof (Date));
    
    /* check for month = January or February */
    if (local_date.months < 3 ) {
        local_date.years--;
	    local_date.months += 12;
	}
	
	a = local_date.years / 100;
	
	/* check for Julian or Gregorian calendar (starts Oct 4th 1582) */
	if (local_date.years > 1582 ||
		(local_date.years == 1582 &&
         (local_date.months > 10 ||
          (local_date.months == 10 && local_date.days >= 4)))) {
             /* Gregorian calendar */
             b = 2 - a + (a / 4);
         } else {
             /* Julian calendar */
             b = 0;
         }
	
	/* add a fraction of hours, minutes and secs to days*/
	days = local_date.days + (double)(local_date.hours / 24.0) + (double)(local_date.minutes / 1440.0) + (double)(local_date.seconds /  86400.0);
    
	/* now get the JD */
	JD = (int)(365.25 * (local_date.years + 4716)) +
    (int)(30.6001 * (local_date.months + 1)) + days + b - 1524.5;
	
	_time = (JD-2440587.5)*86400.;
    
}

void SEClock::printDateAndTime() const {
    std::cout << this->getDateAndTimeStr().c_str() << std::endl;
    
}

irr::core::stringw SEClock::getDateAndTimeStr() const {
    char str[30];
    UTC_to_cockpit_str(this->getSimTime(), str);
    
    return irr::core::stringw(str);
}



